/*
@ClassName JobScheduleServiceImpl
@Description TODO
@Author SubUp
@Date   2022/8/1
@Version 1.0
*/

package com.sunjob.mrojobschedule.service.impl;

import com.sunjob.common.constant.MROConstant;
import com.sunjob.common.domain.scheduleServer.JobSchedule;
import com.sunjob.common.domain.scheduleServer.PlanSchedule;
import com.sunjob.common.domain.scheduleServer.orm.JobResult;
import com.sunjob.common.domain.scheduleServer.orm.PlanResult;
import com.sunjob.common.exception.MROException;
import com.sunjob.common.mroAnno.MethodVerify;
import com.sunjob.common.util.MROUtils;
import com.sunjob.mrojobschedule.mapper.JobScheduleMapper;
import com.sunjob.mrojobschedule.mapper.PlanScheduleMapper;
import com.sunjob.mrojobschedule.service.JobScheduleService;
import com.sunjob.mrojobschedule.service.PlanScheduleService;
import com.sunjob.mrojobschedule.service.ProductScheduleService;
import com.sunjob.mrojobschedule.util.PageExample;
import com.sunjob.mrojobschedule.util.ScheduleUtils;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.sql.Connection;
import java.sql.SQLException;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import java.util.stream.Collectors;

@Service
public class JobScheduleServiceImpl implements JobScheduleService {
    private static final Logger log = LoggerFactory.getLogger(JobScheduleServiceImpl.class);

    @Resource
    private JobScheduleMapper jobScheduleMapper;

    @Resource
    private RedisTemplate redisTemplate;

    @Resource
    private PageExample pageExample;

    @Autowired
    private ProductScheduleService productScheduleService;

    @Resource
    private PlanScheduleService planScheduleService;

    @Resource
    private SqlSessionFactory sqlSessionFactory;

    /**
     * 返回原始作业信息
     * @param pageId
     * @return
     */
    @Override
    @MethodVerify
    public List<JobSchedule> selectJobList(String pageId) {
        Integer page = pageExample.checkPageId(ScheduleUtils.transferToInt(pageId));
        List<JobSchedule> jobsByRedis = getJobsByRedis();
        if(jobsByRedis.size() != 0)
            return pageExample.getPages(jobsByRedis,page);
        return pageExample.getPages(jobScheduleMapper.queryAllJob(),page);
    }

    /**
     * 返回作业调度界面 作业信息
     * @param pageId
     * @return
     */
    @Override
    @MethodVerify
    public List<JobResult> selectJobOrmList(String pageId) {
        List<JobSchedule> jobsByRedis = getJobsByRedis();
        Integer page = pageExample.checkPageId(ScheduleUtils.transferToInt(pageId));
        if(jobsByRedis.size() != 0){
            return pageExample.getPages(conformityPlanParam(jobsByRedis),page);
        }
        log.info("redis search failure ");
        List<JobResult> jobResults = jobScheduleMapper.queryAllJobResult();
        for (JobResult jp:jobResults
             ) {
            List<PlanResult> planResults = planScheduleService.selectPlanOrmById(ScheduleUtils.transferStringByLong(jp.getPlanId()));
            if(planResults.size() == 0 || planResults.size() > 1)
                throw new MROException("plan id occur error",500);
            jp.setPlanResult(planResults.get(0));
        }
        return pageExample.getPages(jobResults,page);
    }

    /**
     * 作业级别返回作业调度界面作业信息
     * @param jobLevel
     * @return
     */
    @Override
    @MethodVerify
    public List<JobResult> selectJobOrmByJobLevel(String jobLevel,String pageId) {
        Integer level = ScheduleUtils.transferToInt(jobLevel);
        ScheduleUtils.enumerateCheck(level,1);
        Integer page = pageExample.checkPageId(ScheduleUtils.transferToInt(pageId));
        List<JobSchedule> jobsByRedis = matchJobLevel(getJobsByRedis(),level);
        if(jobsByRedis.size() != 0){
            return pageExample.getPages(conformityPlanParam(jobsByRedis),page);
        }
        log.info("redis search failure ");
        return pageExample.getPages(jobScheduleMapper.queryJobByLevel(level),page);
    }

    /**
     * 作业反馈状态调度界面作业信息
     * @param jobFeedBack
     * @param pageId
     * @return
     */
    @Override
    @MethodVerify
    public List<JobResult> selectJobOrmByJobFeedBack(String jobFeedBack,String pageId) {
        Integer feedback = ScheduleUtils.transferToInt(jobFeedBack);
        ScheduleUtils.enumerateCheck(feedback,5);
        Integer page = pageExample.checkPageId(ScheduleUtils.transferToInt(pageId));
        List<JobSchedule> jobsByRedis = matchJobFeedBack(getJobsByRedis(),feedback);
        if(jobsByRedis.size() != 0){
            return pageExample.getPages(conformityPlanParam(jobsByRedis),page);
        }
        log.info("redis search failure ");
        return pageExample.getPages(jobScheduleMapper.queryJobByFeedBack(feedback),page);
    }

    /**
     * 技术员工号返回作业调度界面作业信息
     * @param staffId
     * @param pageId
     * @return
     */
    @Override
    @MethodVerify
    public List<JobResult> selectJobOrmByStaffId(String staffId,String pageId) {
        ScheduleUtils.checkName(staffId);
        List<JobSchedule> jobsByRedis = matchJobStaffId(getJobsByRedis(), staffId);
        Integer page = pageExample.checkPageId(ScheduleUtils.transferToInt(pageId));
        if(jobsByRedis.size() != 0){
            return pageExample.getPages(conformityPlanParam(jobsByRedis),page);
        }
        log.info("redis search failure ");
        return pageExample.getPages(jobScheduleMapper.queryJobByStaffId(staffId),page);
    }

    /**
     * 技术员姓名返回作业调度界面作业信息
     * @param staffName
     * @return
     */
    @Override
    @Transactional
    @MethodVerify
    public List<JobResult> selectJobOrmByStaffName(String staffName,String pageId) {
        ScheduleUtils.checkName(staffName);
        List<JobSchedule> jobsByRedis = matchJobStaffName(getJobsByRedis(), staffName);
        Integer page = pageExample.checkPageId(ScheduleUtils.transferToInt(pageId));
        if(jobsByRedis.size() != 0){
            return pageExample.getPages(conformityPlanParam(jobsByRedis),page);
        }
        log.info("redis search failure ");
        return pageExample.getPages(jobScheduleMapper.queryJobByStaffName(staffName),page);
    }

    /**
     * 作业级别、作业反馈状态查询作业数量
     * @param jobLevel
     * @param jobFeedBack
     * @return
     */
    @Override
    @Transactional
    @MethodVerify
    public Integer selectJobCount(String jobLevel, String jobFeedBack) {
        Integer level = ScheduleUtils.transferToInt(jobLevel);
        Integer feedback = ScheduleUtils.transferToInt(jobFeedBack);
        ScheduleUtils.enumerateCheck(level,1);
        ScheduleUtils.enumerateCheck(feedback,5);
        List<JobSchedule> jobsByRedis = matchJobLevel(matchJobFeedBack(getJobsByRedis(), level), feedback);
        int records = jobsByRedis.size();
        if(records != 0)
            return records;
        log.info("redis search failure ");
        return jobScheduleMapper.recordsJob(level,feedback);
    }

    /**
     * 保存作业信息
     * @param job 作业信息
     * @return
     */
    @Override
    @Transactional(isolation = Isolation.DEFAULT,propagation = Propagation.REQUIRES_NEW)
    @MethodVerify
    public Integer insertJob(JobSchedule job) {
        ScheduleUtils.jobScheduleCheck(job);
        /* 设置作业创建时间 */
        job.setCreateTime(LocalDateTime.now());
        /* 设置作业编号 */
        job.setJobId(MROUtils.nextId());
        /* 设置作业创建操作人 */
        /* 设置作业更新时间*/
        job.setUpdateTime(LocalDateTime.now());
        job.setJobExecuteTime(new Date());
        /* 设置作业更新操作人*/
        /* 设置作业记录未删除 */
        job.setIsDelete(1);
        HashOperations<String,Object,Object> hashOperations = redisTemplate.opsForHash();
        hashOperations.put(MROConstant.JOB_MESSAGES,ScheduleUtils.transferStringByLong(job.getJobId()),job);
        log.info("this is successful , redis save message --->"+MROConstant.JOB_MESSAGES);
        return jobScheduleMapper.insertJob(job);
    }

    /**
     * 修改作业的原始信息
     * @param job 作业信息
     * @return
     */
    @Override
    @Transactional
    @MethodVerify
    public Integer updateJob(JobSchedule job) {
        ScheduleUtils.jobScheduleCheck(job);
        job.setUpdateTime(LocalDateTime.now());
        //缺少updateBy
        Integer rt = jobScheduleMapper.updateJob(job);
        if(rt == 1)
            setJobToRedis(job);
        return rt;
    }

    @Override
    public Integer updateJobResult(JobResult jobResult) {
        JobSchedule job = null;
        List<JobSchedule> jobResults = jobScheduleMapper.queryJobPrimById(jobResult.getJobId());
        if(jobResults.size() == 0 || jobResults.size() > 1)
            throw new MROException("job id occur error",500);
        job = jobResults.get(0);
        job.setStaffId(jobResult.getStaffId());
        job.setStaffName(jobResult.getStaffName());
        job.setStaffPosition(jobResult.getStaffPosition());
        job.setUpdateTime(LocalDateTime.now());
        return jobScheduleMapper.updateJob(job);
    }

    /**
     * 修改作业反馈状态
     * @param jobId
     * @param jobFeedBack
     * @return
     */
    @Override
    @MethodVerify
    public Integer updateJobFeedBack(String jobId, String jobFeedBack) {
        Integer feedback = ScheduleUtils.transferToInt(jobFeedBack);
        ScheduleUtils.enumerateCheck(feedback,5);
        Long jobNumber = ScheduleUtils.transferToLong(jobId);
        Integer rt = jobScheduleMapper.updateJobByJobFeedBack(jobNumber, feedback);
        if(rt != 0){
            JobSchedule jobByRedis = getJobByRedis(jobNumber);
            if(jobByRedis != null){
                jobByRedis.setJobFeedBack(feedback);
                setJobToRedis(jobByRedis);
            }

        }
        return rt;
    }

    /**
     * 修改作业级别
     * @param jobId
     * @param jobLevel
     * @return
     */
    @Override
    @MethodVerify
    public Integer updateJobLevel(String jobId, String jobLevel) {
        Integer level = ScheduleUtils.transferToInt(jobLevel);
        ScheduleUtils.enumerateCheck(level,1);
        Long jobNumber = ScheduleUtils.transferToLong(jobId);
        Integer rt = jobScheduleMapper.updateJobByJobLevel(jobNumber,level );
        if(rt != 0){
            JobSchedule jobByRedis = getJobByRedis(jobNumber);
            if(jobByRedis != null){
                jobByRedis.setJobLevel(level);
                setJobToRedis(jobByRedis);
            }
        }
        return rt;
    }

    /**
     * 删除作业的原始信息
     * @param jobId
     * @return
     */
    @Override
    @Transactional
    @MethodVerify
    public Integer deleteJob(String jobId) {
        Long jobNumber = ScheduleUtils.transferToLong(jobId);
        Integer rt = jobScheduleMapper.removeJob(jobNumber);
        if(rt == 1)
            removeJobByJobId(jobNumber);
        return rt;
    }

    /**
     * jobId查询作业调度界面信息
     * @param jobId 作业ID
     * @return
     */
    @Override
    @Transactional
    @MethodVerify
    public List<JobResult> selectJobById(String jobId,String pageId) {
        Integer page = pageExample.checkPageId(ScheduleUtils.transferToInt(pageId));
        Long jobNumber = ScheduleUtils.transferToLong(jobId);
        List<JobSchedule> jobsByRedis = getJobsByRedis();
        List<JobSchedule> jobScheduleList = matchJobId(jobsByRedis,jobNumber);
        if(jobScheduleList.size() != 0)
            return pageExample.getPages(conformityPlanParam(jobScheduleList),page);
        log.info("redis search failure ");
        return pageExample.getPages(jobScheduleMapper.queryJobById(jobNumber),page);
    }


    @Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ)
    public Integer faultHandlerByExamine(PlanSchedule plan) {
        return null;
    }

    @Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ)
    public Integer faultHandler(PlanSchedule plan, JobSchedule job) {
        SqlSession session = sqlSessionFactory.openSession();
        Connection connection = null;
        try{
            connection = session.getConnection();
            connection.setAutoCommit(false);
            connection.commit();
        } catch (SQLException e) {
            e.printStackTrace();
            try {
                connection.rollback();
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
        }finally {
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /* 在Redis中修改JobSchedule */
    public void setJobToRedis(JobSchedule job){
        HashOperations<String,String,JobSchedule> hashOperations = redisTemplate.opsForHash();
        hashOperations.put(MROConstant.JOB_MESSAGES,ScheduleUtils.transferStringByLong(job.getJobId()),job);
        log.info("this is successful , redis update message --->"+MROConstant.PLAN_MESSAGES);
    }

    /* 在Redis中根据jobId删除JobSchedule */
    public void removeJobByJobId(Long jobId){
        HashOperations<String,String,String> hashOperations = redisTemplate.opsForHash();
        hashOperations.delete(MROConstant.JOB_MESSAGES,ScheduleUtils.transferStringByLong(jobId));
        log.info("this is successful , redis delete message --->"+MROConstant.PLAN_MESSAGES);
    }

    /* 在Redis中获取JobSchedule*/
    public List<JobSchedule> getJobsByRedis(){
        HashOperations<String,String,JobSchedule> hashOperations = redisTemplate.opsForHash();
        List<JobSchedule> jobs = hashOperations.values(MROConstant.JOB_MESSAGES);
        return jobs;
    }

    /* JobId在Redis中获取JobSchedule*/
    public JobSchedule getJobByRedis(Long jobId){
        HashOperations<String,String,JobSchedule> hashOperations = redisTemplate.opsForHash();
        return hashOperations.get(MROConstant.JOB_MESSAGES,ScheduleUtils.transferStringByLong(jobId));
    }
    /*JobSchedule转化为JobResult*/
    private List<JobResult> conformityPlanParam(List<JobSchedule> jobs){
        List<JobResult> jobResults = new Vector<>();
        Map<String, String> jobLevelParam = productScheduleService.selectJobLevelParam();
        Map<String, String> jobFeedbackParam = productScheduleService.selectJobFeedBackParam();
        for (JobSchedule js:jobs
             ) {
            JobResult jobResult = new JobResult();
            jobResult.setJobId(js.getJobId());
            jobResult.setPlanId(js.getPlanId());
            List<PlanResult> planResults = planScheduleService.selectPlanOrmById(js.getPlanId().toString());
            if(planResults.size() == 0 || planResults.size() > 1)
                throw new MROException("plan id occur error",500);
            jobResult.setPlanResult(planResults.get(0));
//            List collect = planResults.stream().filter(p -> p.getPlanId() == js.getPlanId()).collect(Collectors.toList());
//            if(collect.size() != 0)
//                jobResult.setPlanResult((PlanResult) collect.get(0));
            jobResult.setCreateBy(js.getCreateBy());
            jobResult.setCreateTime(js.getCreateTime());
            jobResult.setJobExecuteTime(js.getJobExecuteTime()  );
            jobResult.setJobFeedBackExplain(jobFeedbackParam.get(ScheduleUtils.transferStringByInteger(js.getJobFeedBack())));
            jobResult.setLevelExplain(jobLevelParam.get(ScheduleUtils.transferStringByInteger(js.getJobLevel())));
            jobResult.setStaffId(js.getStaffId());
            jobResult.setStaffName(js.getStaffName());
            jobResult.setStaffPosition(js.getStaffPosition());
            jobResults.add(jobResult);
        }
        return jobResults;
    }



    /*JobSchedule 在Redis中过滤jobId*/
    public List<JobSchedule> matchJobId(List<JobSchedule> jobsByRedis, Long jobId) {
        return jobsByRedis.stream()
                .filter(js -> ScheduleUtils.transferStringByLong(js.getJobId()).contains(ScheduleUtils.transferStringByLong(jobId)))
                .collect(Collectors.toList());
    }

    /*JobSchedule 在Redis中过滤jobLevel*/
    public List<JobSchedule> matchJobLevel(List<JobSchedule> jobsByRedis,Integer jobLevel){
        return jobsByRedis.stream().filter(jbr->jbr.getJobLevel()==jobLevel || jobLevel == -1)
                .collect(Collectors.toList());
    }

    /*JobSchedule 在Redis中过滤jobFeedBack*/
    public List<JobSchedule> matchJobFeedBack(List<JobSchedule> jobsByRedis,Integer jobFeedBack){
        return jobsByRedis.stream().filter(jbr->jbr.getJobFeedBack()==jobFeedBack || jobFeedBack == -1)
                .collect(Collectors.toList());
    }

    /*JobSchedule 在Redis中过滤staffId*/
    public List<JobSchedule> matchJobStaffId(List<JobSchedule> jobsByRedis,String staffId){
        return jobsByRedis.stream().filter(jbr->jbr.getStaffId().contains(staffId))
                .collect(Collectors.toList());
    }

    /*JobSchedule 在Redis中过滤staffName*/
    public List<JobSchedule> matchJobStaffName(List<JobSchedule> jobsByRedis,String staffName){
        return jobsByRedis.stream().filter(jbr->jbr.getStaffName().contains(staffName))
                .collect(Collectors.toList());
    }
}
